<template>
  <article class="page page-portscan-web container">
    <h4 class="text-center">端口扫描器（Web）</h4>
    <form role="form">
      <div class="form-group row">
        <label class="col-1 col-form-label">目 标</label>
        <div class="col-10">
          <input type="text" class="form-control" v-model.trim="target" :placeholder="targetPlaceholder">
        </div>
      </div>
      <div class="form-group row">
        <label class="col-1 col-form-label">端 口</label>
        <div class="col-10">
          <input type="text" class="form-control" v-model.trim="port" placeholder="请输入要扫描的端口">
        </div>
      </div>
      <div class="form-group row">
        <label class="col-1 col-form-label">延 迟</label>
        <div class="col-10">
          <input type="text" class="form-control" v-model.trim="timeout" placeholder="请输入延迟，单位ms">
        </div>
      </div>
      <div class="form-group row">
        <label class="col-1 col-form-label">方 式</label>
        <div class="col-10 scantype-wrapper">
          <label><input class="form-check-input" type="radio" value="Image" v-model="scanType">Image</label>
          <label><input class="form-check-input" type="radio" value="WebSocket" v-model="scanType">WebSocket</label>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-1 col-form-label"></label>
        <div class="col-10">
          <x-button type="primary" block :loading="loadingCount > 0" @click="scan">扫 描</x-button>
        </div>
      </div>
      <div class="form-group row">
        <label class="col-1 col-form-label">结 果</label>
        <div class="col-10">
          <textarea class="form-control" v-model.trim="result" rows="10" readonly></textarea>
        </div>
      </div>
    </form>
  </article>
</template>

<script>

export default {
  name: 'portscan-web',
  data () {
    return {
      target: '',
      port: '21,23,80,135,139,445,1433,3389,8080',
      timeout: 1000,
      scanType: 'Image',
      result: '',
      loadingCount: 0
    }
  },
  computed: {
    targetPlaceholder () {
      return this.scanType === 'Image' ? '请输入目标IP或域名（不加http）' : '请输入目标IP或域名（不加ws）'
    }
  },
  methods: {
    // 端口扫描-Image
    scanPort1 (port) {
      let timeout = this.timeout || 100
      let img = new Image()
      img.onerror = () => {
        if (!img) return
        this.loadingCount--
        img = undefined
        this.result += `${this.target}:${port}  open\n`
      }
      img.onload = img.onerror
      this.loadingCount++
      img.src = `http://${this.target}:${port}`
      setTimeout(() => {
        if (!img) return
        this.loadingCount--
        img = undefined
        this.result += `${this.target}:${port}  closed\n`
      }, timeout)
    },
    // 端口扫描-WebSocket
    scanPort2 (port) {
      // let timeout = Math.max(this.timeout || 100, 100)
      let timeout = this.timeout || 100
      let flag = false
      this.loadingCount++
      try {
        let mySocket = new WebSocket(`ws://${this.target}:${port}`)
        // let start = performance.now()
        mySocket.onerror = (e) => {
          // console.log(`Port ${port}: ${performance.now() - start} ms`, this.loadingCount, e)
          // let t = performance.now() - start
          // this.loadingCount--
          // if (t > timeout) {
          //   this.result += `${this.target}:${port}  closed\n`
          // } else {
          //   this.result += `${this.target}:${port}  open\n`
          // }
          console.log(e)
          flag = true
        }
        mySocket.onopen = () => { flag = true }
        mySocket.onclose = () => { flag = true }
        mySocket.onmessage = () => { flag = true }
      } catch (err) {
        // console.log(this.loadingCount, err)
        // this.loadingCount--
        // this.result += `${this.target}:${port}  open\n`
        flag = true
      }
      setTimeout(() => {
        this.loadingCount--
        this.result += `${this.target}:${port}  ${flag ? 'open' : 'closed'}\n`
      }, timeout)
    },
    scanPort (port) {
      this.target = this.target || '127.0.0.1'
      if (this.scanType === 'WebSocket') {
        return this.scanPort2(port)
      } else {
        return this.scanPort1(port)
      }
    },
    scan () {
      this.result = ''
      let ports = this.port.split(',')
      ports.forEach(v => {
        if (/-/.test(v)) {
          var _arr = v.split("-").sort()
          for (var i = parseInt(_arr[0]); i <= parseInt(_arr[1]); i++) {
            this.scanPort(i)
          }
        }else{
          this.scanPort(v)
        }
      })
    }
  }
}
</script>

<style scoped lang="less">
@import "~@/assets/css/_mixins.less";
@import "~@/assets/css/_color.less";
textarea {
  resize: none;
}
.scantype-wrapper {
  label {
    margin-right: 1em;
    vertical-align: -webkit-baseline-middle;
  }
}
</style>
